#include <stdio.h>
#include <stdlib.h>
#include "absyn.h"
#include "tree.h"
#include "canon.h"
#include "util.h"
#include "semant.h"
#include "printtree.h"
#include "assem.h"
#include "frame.h"
#include "codegen.h"
#include "flowgraph.h"
#include "liveness.h"
#include "graph.h"

extern A_exp absyn_root;
extern FILE *yyin;
extern char *yytext;
extern void yyparse();

extern void EM_reset(char*);
extern void destroy(A_exp);

extern G_table node_ins;
extern TAB_table temp_node;

void printFlowGragh(G_graph graph)
{
    G_nodeList nlist;
    static Temp_map map;

    nlist = G_nodes(graph);
    map = Temp_name();
    while(nlist)
    {
        AS_instr instr;
        static int count = 0;
        string str = NULL;
        Temp_tempList defs = FG_def(nlist->head);
        Temp_tempList uses = FG_use(nlist->head);
        instr = G_look(node_ins, nlist->head);

        switch(instr->kind)
        {
        case I_MOVE:
            str = instr->u.MOVE.assem;
            break;
        case I_OPER:
            str = instr->u.OPER.assem;
            break;
        case I_LABEL:
            str = instr->u.LABEL.assem;
            break;
        }

        printf("#%d \"%s\" \t\t\tdef-> ", count++, str);
        while(defs)
        {
            printf("%s ", Temp_look(map, defs->head));
            defs = defs->tail;
        }
        printf("\tuse-> ");
        while(uses)
        {
            printf("%s ", Temp_look(map, uses->head));
            uses = uses->tail;
        }
        printf("\n");
        nlist = nlist->tail;
    }
};

void printConflictGraph(struct COL_conflictGraph lg)
{
    FILE* file;
    G_graph graph = lg.graph;

    G_nodeList nodes = G_nodes(graph);
    G_nodeList ptr1 = nodes, ptr2 = nodes;
    static Temp_map map;

    map = Temp_name();

    while(ptr1)
    {
        Temp_temp t1 = G_nodeInfo(ptr1->head);
        ptr2 = nodes;
        printf("%s: ", Temp_look(map, t1));

        while(ptr2)
        {
            Temp_temp t2 = G_nodeInfo(ptr2->head);
            if (ptr1 != ptr2 &&
                (G_goesTo(ptr1->head, ptr2->head)))
                //|| G_goesTo(ptr2->head, ptr1->head)))
                printf("%s, ", Temp_look(map, t2));
            ptr2 = ptr2->tail;
        }

        printf("\n");
        ptr1 = ptr1->tail;
    }

    file = fopen("conflict.txt", "w");
    G_show(file, nodes, NULL);
}

int main()
{
    FILE *outfile;
    T_stmList list;
    T_stmList listNew, listOld = NULL, listResult = NULL;
    struct C_block block;
    T_stmList ptr;
    AS_instrList instr;
    G_graph flowGraph;
    struct Live_graph liveGraph;

    EM_reset("test.bm");
    if (!yyin)
    {
        fprintf(stderr, "Can't open input file!\n");
        exit(1);
    }

    yyparse();
    if (!absyn_root)
        exit(1);

    list = SEM_transProg(absyn_root);
    outfile = fopen("treeRaw.out","w");
    printStmList(outfile, list);
    fclose(outfile);

    ptr = list;
    while(ptr)
    {
        listNew = C_linearize(ptr->head);
        if (!listOld)
        {
            listResult = listOld = listNew;
        }
        else
        {
            listOld->tail = listNew;
            listOld = listNew;
        }
        ptr = ptr->tail;
    }

    block = C_basicBlocks(listResult);
    listResult = C_traceSchedule(block);
    outfile = fopen("treeRegular.out","w");
    printStmList(outfile, listResult);
    fclose(outfile);

    instr = F_codegen(Tr_outermost()->frame, listResult);
    outfile = fopen("out.asm","w");
    AS_printInstrList(outfile, instr, Temp_name());
    fclose(outfile);
    flowGraph = FG_AssemFlowGraph(instr);
    liveGraph = Live_liveness(flowGraph);

    // print the assem flow graph
    printFlowGragh(flowGraph);
    //printConflictGraph(liveGraph);

    //U_mainEnd();
    exit(0);
}
